/*
 * Out.java
 *
 * Created on June 19, 2007, 1:00 PM
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package io;

import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortOut;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.Variable;

public class OSCOut extends Module {
    private int oscPort; 
    private InetAddress host;
    private String hostString;
    private OSCPortOut oscout; 
    private Variable oscmsg;
    
    public void setHost(String host) {
        try {
            this.host = InetAddress.getByName(host);
            hostString = host;
        } catch (UnknownHostException ex) {
            log("Unkown host: " + host, MSG.ERROR);
        }
    } public String getHost() { return hostString; }

    public void setPort(Integer port) {
        oscPort = port;
    } public Integer getPort() { return oscPort; }

    @Override
    public void start() {
        super.start();
        try {
            oscout = new OSCPortOut(host, oscPort);
            log("Opening output connection on " + java.net.InetAddress.getByName("localhost") + ":" + oscPort, MSG.ANOUNCE);
        } catch (Exception e) {
            throw new IllegalArgumentException("Error while opening OSC port: " + e.getMessage());
        }
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        if (channel!=Channel.CHAIN) return;        
        this.setInVars(in, timestamp, channel);        

        String address = in.getName();
        OSCMessage msg = new OSCMessage(address);
        
        if (in.getDataType().isArray()) { // an array of var this.
            List<Object> oscArguments = ((List<Object>)in.getValue(this));
            int argsnum = oscArguments.size();            
            if (in.getDataType().matches(DataType.VAR, true)) {
                for (int i=0; i<argsnum; i++) {
                    Object arg = oscArguments.get(i);
                    Object argval;
                    if (DataType.findType(arg).matches(DataType.FLOAT))
                        argval = ((Double)arg).floatValue();
                    else argval = arg;
                    msg.addArgument(argval);
                }                
            } else { // an array of identical typed variable.
                for (int i=0; i<argsnum; i++) {
                    Object argval;
                    if (in.getDataType().matches(DataType.FLOAT))
                        argval = ((Double)oscArguments.get(i));
                    else argval = oscArguments.get(i);
                    msg.addArgument(argval);
                }
            }
        } else {
            Object argval;
            
            if (in.getDataType().matches(DataType.FLOAT))
                argval = ((Double)in.getValue(this)).floatValue();
            else argval = in.getValue(this);
            if (!in.getDataType().matches(DataType.EVENT))                    
                msg.addArgument(argval);
        }
        try {
            if (infoFlag) log("Sending " + oscToString(msg), MSG.INFO);
            oscout.send(msg);
        } catch (Exception e) {
            log("Can't send OSC message: " + e.getMessage(), MSG.WARNING);
        }            
    }

    @Override
    public void stop() {
        super.stop();
        if (oscout!=null) oscout.close();
    }

    private String oscToString(OSCMessage msg) {
        String smsg = msg.getAddress() + ":";
        for (Object arg : msg.getArguments())
            smsg += " " + arg + ",";
        return smsg.substring(0, smsg.length()-1);
    }
}